package com.seanliao.nav.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.seanliao.nav.common.domain.dto.ArticleDTO;
import com.seanliao.nav.common.domain.dto.valid.Add;
import com.seanliao.nav.common.domain.dto.valid.Edit;
import com.seanliao.nav.common.domain.vo.ArticleDetailVO;
import com.seanliao.nav.common.domain.vo.ArticleVO;
import com.seanliao.nav.common.exception.BusinessException;
import com.seanliao.nav.common.response.Result;
import com.seanliao.nav.common.response.ResultBuilder;
import com.seanliao.nav.entity.Article;
import com.seanliao.nav.entity.SysUser;
import com.seanliao.nav.security.MyUserDetails;
import com.seanliao.nav.security.PermissionFilter;
import com.seanliao.nav.service.IArticleService;
import com.seanliao.nav.service.ISysUserService;
import com.seanliao.nav.util.CommonUtil;
import com.seanliao.nav.util.SecurityUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;

/**
 * 文章
 *
 * @author Sean_Liao
 * @since 2024-03-06
 */
@RestController
@RequestMapping("/article")
@RequiredArgsConstructor
public class ArticleController {

    private final IArticleService articleService;
    private final ISysUserService userService;

    @Autowired
    @Qualifier("pms")
    private PermissionFilter pms;

    /**
     * 获取文章列表
     */
    @GetMapping("/list")
    @PreAuthorize("@pms.hasPermission('article:list')")
    public Result<IPage<ArticleVO>> listArticle(@RequestParam(value = "currentPage") String currentPageStr,
                                                @RequestParam(value = "pageSize") String pageSizeStr,
                                                @RequestParam String searchStr,
                                                @RequestParam List<String> searchTags,
                                                @RequestParam(defaultValue = "false") Boolean onlyMine,
                                                @RequestParam(defaultValue = "false") Boolean inDraft,
                                                @RequestParam(defaultValue = "false") Boolean isLock
    ) {
        // 分页
        IPage<Map<String, Object>> pp = new Page<>(Long.parseLong(currentPageStr), Long.parseLong(pageSizeStr));
        // 查询体
        QueryWrapper<Object> qw = new QueryWrapper<>();
        // 搜索标签
        if (searchTags != null) {
            List<String> sortedSearchTags = searchTags.stream().sorted().map(o -> "&" + o + "&").toList();
            String searchTagStr = StrUtil.join("%", sortedSearchTags);
            qw.like(StrUtil.isNotBlank(searchTagStr), "tags", searchTagStr);
        }
        // 搜索字符串
        if (StrUtil.isNotBlank(searchStr)) {
            qw.and(qwT -> qwT
                    .or().like("title", searchStr)
                    .or().like("su.nickname", searchStr)
            );
        }
        // 未删除的
        qw.eq("ta.is_deleted", '0');
        // 只看我的
        if (onlyMine) {
            MyUserDetails userDetails = SecurityUtil.getCurrentUser();
            if (userDetails != null) {
                qw.eq("ta.writer", userDetails.getUserId());
            }
        }
        // 草稿箱的
        if (inDraft) {
            MyUserDetails userDetails = SecurityUtil.getCurrentUser();
            if (userDetails != null) {
                qw.eq("ta.writer", userDetails.getUserId());
                qw.eq("ta.is_publish", "0");
            } else {
                qw.eq("ta.is_publish", "1");
            }
        } else {
            qw.eq("ta.is_publish", "1");
        }
        // 锁定中的，需要lock权限
        if (isLock) {
            if (pms.hasPermission("article:lock")) {
                qw.eq("ta.is_lock", "1");
            } else {
                qw.eq("ta.is_lock", "0");
            }
        } else {
            qw.eq("ta.is_lock", "0");
        }
        // 排序
        qw.orderByDesc("ta.publish_time");
        // 查库
        IPage<ArticleVO> resultPage = articleService.listArticle(pp, qw);
        // 返回
        return ResultBuilder.success(resultPage);
    }

    /**
     * 查看文章内容
     */
    @GetMapping("/detail")
    @PreAuthorize("@pms.hasPermission('article:detail')")
    public Result<?> detailArticle(@RequestParam(value = "id") String idStr) {
        Article article = articleService.getById(idStr);
        Assert.notNull(article, () -> new BusinessException("文章不存在"));
        // 数据隔离
        if (!article.getIsPublish()) {
            // 未发布的只能自己查看
            MyUserDetails userDetails = SecurityUtil.getCurrentUser();
            Assert.isTrue(article.getWriter().equals(userDetails.getUserId()), () -> new BusinessException("不可查看该文章"));
        }
        // 打包
        ArticleDetailVO articleDetailVO = BeanUtil.copyProperties(article, ArticleDetailVO.class);
        // 标签
        articleDetailVO.setTagList(CommonUtil.parseTags(article.getTags()));
        // 作者
        SysUser writer = userService.getById(article.getWriter());
        if (writer != null) {
            articleDetailVO.setWriterId(writer.getId());
            articleDetailVO.setWriteName(writer.getNickname());
        }
        // 发布时间
        if (article.getPublishTime() != null) {
            articleDetailVO.setPublishTime(DateUtil.format(article.getPublishTime(), DatePattern.NORM_DATETIME_PATTERN));
        }
        // 返回
        return ResultBuilder.success(articleDetailVO);
    }

    /**
     * 添加中保存（无数据->草稿箱）
     */
    @PostMapping("/add/save")
    @PreAuthorize("@pms.hasPermission('article:write')")
    public Result<?> addSaveArticle(@Validated(Add.class) @RequestBody ArticleDTO articleDTO) {
        // 当前用户
        MyUserDetails userDetails = SecurityUtil.getCurrentUser();
        // 检查标题重复，该用户的草稿箱内标题不可重复，不同玩家可以重复
        Assert.isFalse(articleService.count(new LambdaQueryWrapper<Article>()
                .eq(Article::getWriter, userDetails.getUserId())
                .eq(Article::getTitle, articleDTO.getTitle())
                .eq(Article::getIsPublish, false)
                .eq(Article::getIsDeleted, false)
        ) > 0, () -> new BusinessException("标题已存在"));
        // 实体
        Article article = BeanUtil.copyProperties(articleDTO, Article.class);
        // 标签整合
        article.setTags(CommonUtil.genTags(articleDTO.getTagList()));
        // 作者
        article.setWriter(userDetails.getUserId());
        // 状态
        article.setIsPublish(false);
        article.setIsPrivate(false);
        // 入库
        if (articleService.save(article)) {
            // 返回一个id，使前端下次点击保存时，使用/edit/save接口
            return ResultBuilder.success(article.getId());
        } else {
            return ResultBuilder.fail("数据写库异常");
        }
    }

    /**
     * 添加中发布
     */
    @PostMapping("/add/publish")
    @PreAuthorize("@pms.hasPermission('article:write')")
    public Result<?> addPublishArticle(@Validated(Add.class) @RequestBody ArticleDTO articleDTO) {
        // 当前用户
        MyUserDetails userDetails = SecurityUtil.getCurrentUser();
        // 检查标题重复
        Assert.isFalse(articleService.count(new LambdaQueryWrapper<Article>()
                .eq(Article::getTitle, articleDTO.getTitle())
                .eq(Article::getIsPublish, true)
                .eq(Article::getIsDeleted, false)
        ) > 0, () -> new BusinessException("标题已存在"));
        // 实体
        Article article = BeanUtil.copyProperties(articleDTO, Article.class);
        // 标签整合
        article.setTags(CommonUtil.genTags(articleDTO.getTagList()));
        // 状态
        article.setIsPublish(true);
        article.setIsPrivate(false);
        // 作者
        article.setWriter(userDetails.getUserId());
        // 入库
        if (articleService.save(article)) {
            // 返回一个id，使前端下次点击保存时，使用/edit/save接口
            return ResultBuilder.success(article.getId());
        } else {
            return ResultBuilder.fail("数据写库异常");
        }
    }

    /**
     * 编辑中保存
     */
    @PostMapping("/edit/save")
    @PreAuthorize("@pms.hasPermission('article:write')")
    public Result<?> editSaveArticle(@Validated(Edit.class) @RequestBody ArticleDTO articleDTO) {
        // 当前用户
        MyUserDetails userDetails = SecurityUtil.getCurrentUser();
        // 旧数据
        Article article = articleService.getById(articleDTO.getId());
        Assert.notNull(article, () -> new BusinessException("文章不存在"));
        // 作者才可编辑
        Assert.isTrue(userDetails.getUserId().equals(article.getWriter()), () -> new BusinessException("文章权限错误"));
        // 检查标题重复
        Assert.isFalse(articleService.count(new LambdaQueryWrapper<Article>()
                .eq(Article::getTitle, articleDTO.getTitle())
                .ne(Article::getId, articleDTO.getId())
                .eq(Article::getIsDeleted, false)
                // 下面这两个判断是草稿箱内的判断
                .eq(!article.getIsPublish(), Article::getIsPublish, false)
                .eq(!article.getIsPublish(), Article::getWriter, userDetails.getUserId())
        ) > 0, () -> new BusinessException("标题已存在"));
        // 更新体
        Article updateArticle = new Article();
        updateArticle.setId(article.getId());
        updateArticle.setTitle(articleDTO.getTitle());
        updateArticle.setTags(CommonUtil.genTags(articleDTO.getTagList()));
        updateArticle.setContent(articleDTO.getContent());
        // 入库
        if (articleService.updateById(updateArticle)) {
            return ResultBuilder.success();
        } else {
            return ResultBuilder.fail("数据写库异常");
        }
    }

    /**
     * 编辑中发布
     */
    @PostMapping("/edit/publish")
    @PreAuthorize("@pms.hasPermission('article:write')")
    public Result<?> editPublishArticle(@Validated(Edit.class) @RequestBody ArticleDTO articleDTO) {
        // 当前用户
        MyUserDetails userDetails = SecurityUtil.getCurrentUser();
        // 旧数据
        Article article = articleService.getById(articleDTO.getId());
        Assert.notNull(article, () -> new BusinessException("文章不存在"));
        // 作者才可发布
        Assert.isTrue(userDetails.getUserId().equals(article.getWriter()), () -> new BusinessException("文章权限错误"));
        // 已发布的不可重新发布
        Assert.isFalse(article.getIsPublish(), () -> new BusinessException("不可重复发布"));
        // 检查标题重复
        Assert.isFalse(articleService.count(new LambdaQueryWrapper<Article>()
                .eq(Article::getTitle, articleDTO.getTitle())
                .ne(Article::getId, articleDTO.getId())
                .eq(Article::getIsDeleted, false)
        ) > 0, () -> new BusinessException("标题已存在"));
        // 更新体
        Article updateArticle = new Article();
        updateArticle.setId(article.getId());
        updateArticle.setTitle(articleDTO.getTitle());
        updateArticle.setTags(CommonUtil.genTags(articleDTO.getTagList()));
        updateArticle.setContent(article.getContent());
        // 发布字段
        updateArticle.setIsPublish(true);
        updateArticle.setPublishTime(LocalDateTime.now());
        // 入库
        if (articleService.updateById(updateArticle)) {
            return ResultBuilder.success();
        } else {
            return ResultBuilder.fail("数据写库异常");
        }
    }

    /**
     * 发布
     * 不保存内容，直接修改文章发布状态
     */
    @PostMapping("/publish")
    @PreAuthorize("@pms.hasPermission('article:write')")
    public Result<?> publishArticle(@Validated(Edit.class) @RequestBody ArticleDTO articleDTO) {
        // 当前用户
        MyUserDetails userDetails = SecurityUtil.getCurrentUser();
        // 旧数据
        Article article = articleService.getById(articleDTO.getId());
        Assert.notNull(article, () -> new BusinessException("文章不存在"));
        // 作者才可发布
        Assert.isTrue(userDetails.getUserId().equals(article.getWriter()), () -> new BusinessException("文章权限错误"));
        // 已发布的不可重新发布
        Assert.isFalse(article.getIsPublish(), () -> new BusinessException("不可重复发布"));
        // 更新体
        Article updateArticle = new Article();
        // 发布字段
        updateArticle.setIsPublish(true);
        updateArticle.setPublishTime(LocalDateTime.now());
        // 入库
        if (articleService.updateById(updateArticle)) {
            return ResultBuilder.success();
        } else {
            return ResultBuilder.fail("数据写库异常");
        }
    }

    /**
     * 删除文章
     */
    @PostMapping("/remove")
    @PreAuthorize("@pms.hasPermission('article:write')")
    public Result<?> removeArticle(@RequestBody ArticleDTO articleDTO) {
        // 当前用户
        MyUserDetails userDetails = SecurityUtil.getCurrentUser();
        // 旧数据
        Article article = articleService.getById(articleDTO.getId());
        Assert.notNull(article, () -> new BusinessException("文章不存在"));
        // 作者才可发布
        Assert.isTrue(userDetails.getUserId().equals(article.getWriter()), () -> new BusinessException("文章权限错误"));
        // 入库
        if (articleService.removeById(article.getId())) {
            return ResultBuilder.success();
        } else {
            return ResultBuilder.fail("数据写库异常");
        }
    }

    /**
     * 草稿数量
     */
    @GetMapping("/draft-count")
    @PreAuthorize("@pms.hasPermission('article:write')")
    public Result<?> countDraft() {
        // 当前用户
        MyUserDetails userDetails = SecurityUtil.getCurrentUser();
        // 我数数
        long count = articleService.count(new LambdaQueryWrapper<Article>()
                .eq(Article::getWriter, userDetails.getUserId())
                .eq(Article::getIsPublish, false)
        );
        return ResultBuilder.success(count);
    }

    /**
     * 锁定/解锁文章
     */
    @PostMapping("/lock")
    @PreAuthorize("@pms.hasPermission('article:lock')")
    public Result<?> lockArticle(@RequestBody ArticleDTO articleDTO) {
        // 更新体
        Article updateArticle = new Article();
        updateArticle.setId(articleDTO.getId());
        updateArticle.setIsLock(articleDTO.getIsLock());
        // 入库
        if (articleService.updateById(updateArticle)) {
            return ResultBuilder.success(articleDTO.getIsLock());
        } else {
            return ResultBuilder.fail("数据写库异常");
        }
    }

    /**
     * 强制删除文章（管理员）
     * 无视数据隔离
     */
    @PostMapping("/remove-force")
    @PreAuthorize("@pms.hasPermission('article:lockForce')")
    public Result<?> removeArticleForce(@RequestBody ArticleDTO articleDTO) {
        return ResultBuilder.fail();
    }

}
